Add simple tests, cleanup
authorRaph Levien <raph@google.com>
Fri, 27 Jan 2017 00:01:36 +0000 (16:01 -0800)
committerRaph Levien <raph@google.com>
Fri, 27 Jan 2017 19:40:58 +0000 (11:40 -0800)
Tests for existence for dep-info output in simple compilation cases.

Deletes the dep-info file if it fails (for example, if it can't find
one of the dep-info inputs).

src/cargo/ops/cargo_rustc/output_depinfo.rs
tests/dep-info.rs [new file with mode: 0644]

index 188956187a89f5f99b5e41472bf21e8788893275..c559e4741eeeb6406ebd379f43cb0c157e6fdfc9 100644 (file)
@@ -1,6 +1,6 @@
 use std::collections::HashSet;
-use std::io::{Write, BufWriter};
-use std::fs::File;
+use std::io::{Write, BufWriter, ErrorKind};
+use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 
 use ops::{Context, Unit};
@@ -22,10 +22,9 @@ fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResul
 fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<'a, 'b>,
     unit: &Unit<'a>, visited: &mut HashSet<Unit<'a>>) -> CargoResult<()>
 {
-    if visited.contains(unit) {
+    if !visited.insert(unit.clone()) {
         return Ok(());
     }
-    visited.insert(unit.clone());
 
     // Add dependencies from rustc dep-info output (stored in fingerprint directory)
     let dep_info_loc = fingerprint::dep_info_loc(context, unit);
@@ -33,6 +32,10 @@ fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<
         for path in paths {
             deps.insert(path);
         }
+    } else {
+        debug!("can't find dep_info for {:?} {:?}",
+            unit.pkg.package_id(), unit.profile);
+        return Err(internal("dep_info missing"));
     }
 
     // Add rerun-if-changed dependencies
@@ -56,18 +59,32 @@ fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<
 pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
     let mut deps = HashSet::new();
     let mut visited = HashSet::new();
-    add_deps_for_unit(&mut deps, context, unit, &mut visited)?;
+    let success = add_deps_for_unit(&mut deps, context, unit, &mut visited).is_ok();
     let basedir = None; // TODO
     for (_filename, link_dst, _linkable) in context.target_filenames(unit)? {
         if let Some(link_dst) = link_dst {
             let output_path = link_dst.with_extension("d");
-            let target_fn = render_filename(link_dst, basedir)?;
-            let mut outfile = BufWriter::new(File::create(output_path)?);
-            write!(outfile, "{}:", target_fn)?;
-            for dep in &deps {
-                write!(outfile, " {}", render_filename(dep, basedir)?)?;
+            if success {
+                let mut outfile = BufWriter::new(File::create(output_path)?);
+                let target_fn = render_filename(link_dst, basedir)?;
+                write!(outfile, "{}:", target_fn)?;
+                for dep in &deps {
+                    write!(outfile, " {}", render_filename(dep, basedir)?)?;
+                }
+                writeln!(outfile, "")?;
+            } else {
+                // dep-info generation failed, so delete output file. This will usually
+                // cause the build system to always rerun the build rule, which is correct
+                // if inefficient.
+                match fs::remove_file(output_path) {
+                    Err(err) => {
+                        if err.kind() != ErrorKind::NotFound {
+                            return Err(err.into());
+                        }
+                    }
+                    _ => ()
+                }
             }
-            writeln!(outfile, "")?;
         }
     }
     Ok(())
diff --git a/tests/dep-info.rs b/tests/dep-info.rs
new file mode 100644 (file)
index 0000000..2f0513e
--- /dev/null
@@ -0,0 +1,79 @@
+extern crate cargotest;
+extern crate hamcrest;
+
+use cargotest::support::{basic_bin_manifest, main_file, execs, project};
+use hamcrest::{assert_that, existing_file};
+
+#[test]
+fn build_dep_info() {
+    let p = project("foo")
+        .file("Cargo.toml", &basic_bin_manifest("foo"))
+        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));
+
+    assert_that(p.cargo_process("build"), execs().with_status(0));
+
+    let depinfo_bin_path = &p.bin("foo").with_extension("d");
+
+    assert_that(depinfo_bin_path, existing_file());
+}
+
+#[test]
+fn build_dep_info_lib() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [[example]]
+            name = "ex"
+            crate-type = ["lib"]
+        "#)
+        .file("src/lib.rs", "")
+        .file("examples/ex.rs", "");
+
+    assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+    assert_that(&p.example_lib("ex", "lib").with_extension("d"), existing_file());
+}
+
+
+#[test]
+fn build_dep_info_rlib() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [[example]]
+            name = "ex"
+            crate-type = ["rlib"]
+        "#)
+        .file("src/lib.rs", "")
+        .file("examples/ex.rs", "");
+
+    assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+    assert_that(&p.example_lib("ex", "rlib").with_extension("d"), existing_file());
+}
+
+#[test]
+fn build_dep_info_dylib() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [[example]]
+            name = "ex"
+            crate-type = ["dylib"]
+        "#)
+        .file("src/lib.rs", "")
+        .file("examples/ex.rs", "");
+
+    assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+    assert_that(&p.example_lib("ex", "dylib").with_extension("d"), existing_file());
+}